<template>
	<view v-if="value" class="tn-select-class tn-select">
		<tn-popup v-model="value" mode="bottom" :popup="false" length="auto" :safeAreaInsetBottom="safeAreaInsetBottom"
			:maskCloseable="maskCloseable" :zIndex="elZIndex" @close="close">
			<view class="tn-select__content">
				<!-- 头部 -->
				<view class="tn-select__content__header" @touchmove.stop.prevent>
					<view class="tn-select__content__header__btn tn-select__content__header--cancel"
						:style="{ color: cancelColor }" hover-class="tn-hover-class" hover-stay-time="150"
						@tap="getResult('cancel')">{{ cancelText }}</view>
					<view class="tn-select__content__header__title">{{ title }}</view>
					<view class="tn-select__content__header__btn tn-select__content__header--confirm"
						:style="{ color: confirmColor }" hover-class="tn-hover-class" hover-stay-time="150"
						@tap="getResult('confirm')">{{ confirmText }}</view>
				</view>
				<!-- 列表内容 -->
				<view class="tn-select__content__body">
					<picker-view class="tn-select__content__body__view" :value="defaultSelector" @pickstart="pickStart"
						@pickend="pickEnd" @change="columnChange">
						<picker-view-column v-for="(item, index) in columnData" :key="index">
							<view class="tn-select__content__body__item" v-for="(sub_item, sub_index) in item"
								:key="sub_index">
								<view class="tn-text-ellipsis">
									{{ sub_item[labelName] }}
								</view>
							</view>
						</picker-view-column>
					</picker-view>
				</view>
			</view>
		</tn-popup>
	</view>
</template>

<script>
	export default {
		name: 'tn-select',
		props: {
			value: {
				type: Boolean,
				default: false
			},
			// 列表模式
			// single 单列 multi 多列 multi-auto 多列联动
			mode: {
				type: String,
				default: 'single'
			},
			// 列数据
			list: {
				type: Array,
				default () {
					return []
				}
			},
			// value属性名
			valueName: {
				type: String,
				default: 'value'
			},
			// label属性名
			labelName: {
				type: String,
				default: 'label'
			},
			// 当mode=multi-auto时，children的属性名
			childName: {
				type: String,
				default: 'children'
			},
			// 默认值
			defaultValue: {
				type: Array,
				default () {
					return [0]
				}
			},
			// 顶部标题
			title: {
				type: String,
				default: ''
			},
			// 取消按钮文字
			cancelText: {
				type: String,
				default: '取消'
			},
			// 取消按钮文字颜色
			cancelColor: {
				type: String,
				default: ''
			},
			// 确认按钮文字
			confirmText: {
				type: String,
				default: '确认'
			},
			// 确认按钮文字颜色
			confirmColor: {
				type: String,
				default: ''
			},
			// 点击遮罩关闭
			maskCloseable: {
				type: Boolean,
				default: true
			},
			// 预留安全区域
			safeAreaInsetBottom: {
				type: Boolean,
				default: false
			},
			// zIndex
			zIndex: {
				type: Number,
				default: 0
			}
		},
		computed: {
			elZIndex() {
				return this.zIndex ? this.zIndex : this.$t.zIndex.popup
			}
		},
		data() {
			return {
				// 列是否还在滑动中，微信小程序如果在滑动中就点确定，结果可能不准确
				moving: false,
				// 用户保存当前列的索引，用于判断下一次变化时改变的列
				defaultSelector: [0],
				// picker-view数据
				columnData: [],
				// 保存用户选择的结果
				selectValue: [],
				// 上一次改变时的index
				lastSelectIndex: [],
				// 列数
				columnNum: 0
			}
		},
		watch: {
			// 在select弹起的时候，重新初始化所有数据
			value: {
				handler(val) {
					if (val) setTimeout(() => this.init(), 10)
				},
				immediate: true
			}
		},
		methods: {
			// 标识滑动开始，只有微信小程序才有这样的事件
			pickStart() {
				// #ifdef MP-WEIXIN
				this.moving = true;
				// #endif
			},
			// 标识滑动结束
			pickEnd() {
				// #ifdef MP-WEIXIN
				this.moving = false;
				// #endif
			},
			init() {
				this.setColumnNum()
				this.setDefaultSelector()
				this.setColumnData()
				this.setSelectValue()
			},
			// 获取默认选中列下标
			setDefaultSelector() {
				// 如果没有传入默认值，生成用0填充长度为columnNum的数组
				this.defaultSelector = this.defaultValue.length === this.columnNum ? this.defaultValue : Array(this
					.columnNum).fill(0)
				this.lastSelectIndex = this.$t.deepClone(this.defaultSelector)
			},
			getDataList(data) {
				if (!data || !Array.isArray(data)) {
					return data
				}

				// 递归处理数据，删除空的children属性
				const processData = (items) => {
					if (!Array.isArray(items)) return items

					return items.map(item => {
						if (item && typeof item === 'object') {
							// 如果children是空数组，删除这个属性
							if (item[this.childName] && Array.isArray(item[this.childName]) && item[this
									.childName].length === 0) {
								delete item[this.childName]
							}
							// 如果children存在且有数据，递归处理
							else if (item[this.childName] && Array.isArray(item[this.childName]) && item[this
									.childName].length > 0) {
								item[this.childName] = processData(item[this.childName])
							}
						}
						return item
					})
				}

				return processData(data)
			},
			// 计算列数
			setColumnNum() {
				// 单列的数量为1
				if (this.mode === 'single') this.columnNum = 1
				// 多列时取list的长度
				else if (this.mode === 'multi') this.columnNum = this.list.length
				// 多列联动时，通过遍历list的第一个元素，得出有多少列
				else if (this.mode === 'multi-auto') {
					let num = 1
					let column = this.getDataList(this.list)
					// 如果存在children属性，再次遍历
					console.log('column', column)
					while (column[0][this.childName]) {
						column = column[0] ? column[0][this.childName] : {},
							num++
					}
					this.columnNum = num
				}
			},
			// 获取需要展示在picker中的列数据
			setColumnData() {
				let data = []
				this.selectValue = []
				if (this.mode === 'multi-auto') {
					// 获取所有数据中的第一个元素
					let column = this.list[this.defaultSelector.length ? this.defaultSelector[0] : 0]
					// 通过循环所有列数，再根据设定列的数组，得出当前需要渲染的整个列数组
					for (let i = 0; i < this.columnNum; i++) {
						// 第一列默认为整个list数组
						if (i === 0) {
							data[i] = this.list
							column = column[this.childName]
						} else {
							// 大于第一列时，判断是否有默认选中的，如果没有就用该列的第一项
							data[i] = column
							column = column[this.defaultSelector[i]][this.childName]
						}
					}
				} else if (this.mode === 'single') {
					data[0] = this.list
				} else {
					data = this.list
				}
				this.columnData = data
			},
			// 获取默认选中的值，如果没有设置，则默认选中第一项
			setSelectValue() {
				let tmp = null
				for (let i = 0; i < this.columnNum; i++) {
					tmp = this.columnData[i][this.defaultSelector[i]]
					let data = {
						value: tmp ? tmp[this.valueName] : null,
						label: tmp ? tmp[this.labelName] : null
					}
					// 判断是否存在额外的参数
					if (tmp && tmp.extra) data.extra = tmp.extra
					this.selectValue.push(data)
				}
			},
			// 列选项
			columnChange(event) {
				let index = null
				let columnIndex = event.detail.value

				this.selectValue = []
				if (this.mode === 'multi-auto') {
					// 对比前后两个数组，判断变更的是那一列
					this.lastSelectIndex.map((v, idx) => {
						if (v != columnIndex[idx]) index = idx
					})
					this.defaultSelector = columnIndex
					// 当前变化列的下一列的数据，需要获取上一列的数据，同时需要指定是上一列的第几个的children，再往后的
					// 默认是队列的第一个为默认选项
					for (let i = index + 1; i < this.columnNum; i++) {
						this.columnData[i] = this.columnData[i - 1][i - 1 == index ? columnIndex[index] : 0][this
							.childName
						]
						this.defaultSelector[i] = 0
					}
					// 在历遍的过程中，可能由于上一步修改this.columnData，导致产生连锁反应，程序触发columnChange，会有多次调用
					// 只有在最后一次数据稳定后的结果是正确的，此前的历遍中，可能会产生undefined，故需要判断
					columnIndex.map((item, index) => {
						let data = this.columnData[index][columnIndex[index]]
						let tmp = {
							value: data ? data[this.valueName] : null,
							label: data ? data[this.labelName] : null
						}
						if (data && data.extra !== undefined) tmp.extra = data.extra
						this.selectValue.push(tmp)
					})
					this.lastSelectIndex = columnIndex
				} else if (this.mode === 'single') {
					let data = this.columnData[0][columnIndex[0]]
					let tmp = {
						value: data ? data[this.valueName] : null,
						label: data ? data[this.labelName] : null
					}
					if (data && data.extra !== undefined) tmp.extra = data.extra
					this.selectValue.push(tmp)
				} else if (this.mode === 'multi') {
					columnIndex.map((item, index) => {
						let data = this.columnData[index][columnIndex[index]]
						let tmp = {
							value: data ? data[this.valueName] : null,
							label: data ? data[this.labelName] : null
						}
						if (data && data.extra !== undefined) tmp.extra = data.extra
						this.selectValue.push(tmp)
					})
				}
			},
			close() {
				this.$emit('input', false)
			},
			getResult(event = null) {
				// #ifdef MP-WEIXIN
				if (this.moving) return;
				// #endif
				if (event) this.$emit(event, this.selectValue)
				this.close()
			}
		}
	}
</script>

<style lang="scss" scoped>
	.tn-select {

		&__content {
			position: relative;

			&__header {
				position: relative;
				display: flex;
				flex-direction: row;
				width: 100%;
				height: 90rpx;
				padding: 0 40rpx;
				align-items: center;
				justify-content: space-between;
				box-sizing: border-box;
				font-size: 30rpx;
				background-color: #FFFFFF;

				&__btn {
					padding: 16rpx;
					box-sizing: border-box;
					text-align: center;
					text-decoration: none;
				}

				&__title {
					color: $tn-font-color;
				}

				&--cancel {
					color: $tn-font-sub-color;
				}

				&--confirm {
					color: $tn-main-color;
				}
			}

			&__body {
				width: 100%;
				height: 500rpx;
				overflow: hidden;
				background-color: #FFFFFF;

				&__view {
					height: 100%;
					box-sizing: border-box;
				}

				&__item {
					display: flex;
					flex-direction: row;
					align-items: center;
					justify-content: center;
					font-size: 32rpx;
					color: $tn-font-color;
					padding: 0 8rpx;
				}
			}
		}

	}
</style>